/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 */
package org.is.city.pointsmanager;

import com.vividsolutions.jts.geom.Point;
import java.awt.BorderLayout;

import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import net.miginfocom.swing.MigLayout;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.geometry.DirectPosition2D;

import org.geotools.map.MapLayer;
import org.geotools.styling.Style;
import org.geotools.swing.JMapPane;
import org.geotools.swing.control.DnDList;
import org.geotools.swing.control.DnDListModel;
import org.geotools.swing.styling.JSimpleStyleDialog;
import org.is.city.routemanager.Layers.PointsLayer;
import org.is.city.routemanager.MultiPointGuideAction;
import org.is.city.routemanager.Route;
import org.is.city.routemanager.RoutePanel;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;

/**
 * Displays a list of the map layers in an associated {@linkplain JMapPane} and
 * provides controls to set the visibility, selection and style of each layer.
 * <p>
 * Implementation note: DefaultMapContext stores its list of MapLayer objects
 * in rendering order, ie. the layer at index 0 is rendererd first, followed by
 * index 1 etc. MapLayerTable stores its layers in the reverse order since it
 * is more intuitive for the user to think of a layer being 'on top' of other
 * layers.
 *
 * @author Michael Bedward
 * @since 2.6
 * @source $URL: http://svn.osgeo.org/geotools/trunk/modules/unsupported/swing/src/main/java/org/geotools/swing/MapLayerTable.java $
 * @version $Id: MapLayerTable.java 35310 2010-04-30 10:32:15Z jive $
 */
public class POImanager extends JPanel {

    private static final long serialVersionUID = -8461593609237317561L;
    private static final ResourceBundle stringRes = ResourceBundle.getBundle("META-INF/Text");
    private JMapPane pane;
    private DnDListModel<RoutePoint> listModel;
    private DnDList<RoutePoint> list;
    private JScrollPane scrollPane;

    /* For detecting mouse double-clicks */
    private static final long DOUBLE_CLICK_TIME = 500;
    private long lastClickTime = 0;
    RoutePanel routePanel;

    /*
     * Whether to prompt for confirmation before removing a layer.
     * @todo introduce a setter or property for this
     */
    private boolean confirmRemove = true;

    /**
     * Default constructor. A subsequent call to {@linkplain #setMapPane}
     * will be required.
     */
    public POImanager() {
        init();
    }

    /**
     * Constructor.
     * @param pane the map pane this MapLayerTable will service.
     */
    public POImanager(JMapPane pane, RoutePanel routePanel) {
        setMapPane(pane);
        init();
        this.routePanel = routePanel;

    }

    public void setMapPane(JMapPane pane) {
        this.pane = pane;
    }

    public RoutePanel getRoutePanel() {
        return routePanel;
    }

    public void setRoutePanel(RoutePanel routePanel) {
        this.routePanel = routePanel;
        init();
    }
    Route selectedRoute;

    public Route getSelectedRoute() {
        return selectedRoute;
    }

    public void onRouteLayerSelected(Route route) {

        if(route==null){
            listModel=new DnDListModel<RoutePoint>();
            list.setModel(listModel);
            list.repaint();
            selectedRoute=null;
            return;
        }
        this.selectedRoute = route;
        listModel = new DnDListModel<RoutePoint>();
        list.setModel(listModel);

        // Listen for drag-reordering of the list contents which
        // will be received via the contentsChanged method
        listModel.addListDataListener(new ListDataListener() {

            public void intervalAdded(ListDataEvent e) {
            }

            public void intervalRemoved(ListDataEvent e) {
            }

            public void contentsChanged(ListDataEvent e) {
                onReorderPoints(e);
            }
        });

        if (route.getPointsLayer().getFeatureSource() == null) {
            System.out.println("Your route somewhy without featuresource");
            return;
        }

        LinkedList<RoutePoint> routePointsList = route.getRoutePointsList();
        Iterator<RoutePoint> iterator = routePointsList.iterator();
        while (iterator.hasNext()) {
            listModel.addItem(iterator.next());
        }
        repaint();
        list.repaint();

    }

    /**
     * Repaint the list item associated with the specified MapLayer object
     *
     * @param layer the map layer
     */
    public void repaint(RoutePoint point) {
        int index = listModel.indexOf(point);
        list.repaint(list.getCellBounds(index, index));
    }

    /**
     * Called by the constructor. This method lays out the components that
     * make up the MapLayerTable and registers a mouse listener.
     */
    private void init() {
        listModel = new DnDListModel<RoutePoint>();
        list = new DnDList<RoutePoint>(listModel) {

            private static final long serialVersionUID = 1289744440656016412L;
            /*
             * We override setToolTipText to provide tool tips
             * for the control labels displayed for each list item
             */

            @Override
            public String getToolTipText(MouseEvent e) {
                int item = list.locationToIndex(e.getPoint());

                if (item >= 0) {
                    Rectangle r = list.getCellBounds(item, item);
                    if (r.contains(e.getPoint())) {
                        java.awt.Point p = new java.awt.Point(e.getPoint().x, e.getPoint().y - r.y);

                        if (MapLayerTableCellRenderer.hitRemoveLabel(p)) {
                            return stringRes.getString("Delete_point");

                        } else if (MapLayerTableCellRenderer.hitNameLabel(p)) {
                            return stringRes.getString("rename_layer");
                        }
                    }
                }

                return null;
            }
        };

        // Listen for drag-reordering of the list contents which
        // will be received via the contentsChanged method
        listModel.addListDataListener(new ListDataListener() {

            public void intervalAdded(ListDataEvent e) {
            }

            public void intervalRemoved(ListDataEvent e) {
            }

            public void contentsChanged(ListDataEvent e) {
                onReorderPoints(e);
            }
        });


        list.setCellRenderer(new MapLayerTableCellRenderer());
        list.setFixedCellHeight(MapLayerTableCellRenderer.getCellHeight());

        list.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                long clickTime = System.currentTimeMillis();
                boolean doubleClick = clickTime - lastClickTime < DOUBLE_CLICK_TIME;
                lastClickTime = clickTime;
                onLayerItemClicked(e, doubleClick);
            }
        });

        scrollPane = new JScrollPane(list,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

        scrollPane.setBorder(BorderFactory.createTitledBorder(stringRes.getString("points_panel_title")));

        JPanel btnPanel = new JPanel(new MigLayout());


        Icon addIcon = new ImageIcon(POImanager.class.getResource("/add.png"));
        JToggleButton btnAddPointsToRoute = new JToggleButton(addIcon);
        btnAddPointsToRoute.addActionListener(new MultiPointGuideAction(btnAddPointsToRoute, getRoutePanel(), pane, "n"));
        btnAddPointsToRoute.setToolTipText("Добавить точки к маршруту");
        btnPanel.add(btnAddPointsToRoute);



        setLayout(new BorderLayout());
        add(scrollPane, BorderLayout.CENTER);
        add(btnPanel, BorderLayout.SOUTH);
    }

    /**
     * Handle a mouse click on a cell in the JList that displays
     * layer names and states.
     *
     * @param ev the mouse event
     * @param doubleClick true if this is the second click of a double-click; false otherwise
     */
    private void onLayerItemClicked(MouseEvent ev, boolean doubleClick) {
        int item = list.locationToIndex(ev.getPoint());

        if (item >= 0) {
            Rectangle r = list.getCellBounds(item, item);
            if (r.contains(ev.getPoint())) {
                RoutePoint element = listModel.getElementAt(item);
                java.awt.Point p = new java.awt.Point(ev.getPoint().x, ev.getPoint().y - r.y);
                if (MapLayerTableCellRenderer.hitRemoveLabel(p)) {
                    doRemovePointWithConfirm(element);
                } else {
                    Route selectedRoute1 = getSelectedRoute();
                    PointsLayer pointsLayer = selectedRoute1.getPointsLayer();
                    List<AttributeDescriptor> attributeDescriptors = pointsLayer.getSimpleFeatureSource().getSchema().getAttributeDescriptors();
                    Iterator<AttributeDescriptor> iterator = attributeDescriptors.iterator();
                    while (iterator.hasNext()) {
                        AttributeDescriptor next = iterator.next();
                        //System.out.println(next.getLocalName());
                    }
                    FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
                    Filter filter = ff.equals(ff.property("name"), ff.literal(element.getFeature().getProperty("name").getValue().toString()));

                    try {
                        SimpleFeatureCollection features = pointsLayer.getSimpleFeatureSource().getFeatures(filter);
                        if (features.size() > 0) {
                            SimpleFeatureIterator features1 = features.features();
                            SimpleFeature next = features1.next();
                            features1.close();

                        }
                        //System.out.println(features.size());

                    } catch (IOException ex) {
                        Logger.getLogger(POImanager.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

            }
        }
    }

    /**
     * Show a style dialog to create a new Style for the layer
     *
     * @param layer the layer to be styled
     */
    private void doSetStyle(MapLayer layer) {
        Style style = JSimpleStyleDialog.showDialog(this, layer);
        if (style != null) {
            layer.setStyle(style);
        }
    }

    /**
     * Prompt for a new title for the layer
     *
     * @param layer the layer to be renamed
     */
    private void doSetLayerName(MapLayer layer) {
        String name = JOptionPane.showInputDialog(stringRes.getString("new_layer_name_message"));
        if (name != null && name.trim().length() > 0) {
            layer.setTitle(name.trim());
        }
    }

    /**
     * Вызывается кликом по значку "удалить маршрут"
     *
     * @param layer the layer to remove
     */
    private void doRemovePointWithConfirm(RoutePoint element) {
        if (selectedRoute.getRoutePointsList().size() == 2) {
            int confirm = JOptionPane.showConfirmDialog(null,
                    stringRes.getString("confirm_remove_point_message_2"),
                    stringRes.getString("confirm_remove_point"),
                    JOptionPane.YES_NO_OPTION);
            if (confirm != JOptionPane.YES_OPTION) {
                return;
            } else {
                routePanel.doRemoveRoute(selectedRoute);
                this.onRouteLayerSelected(null);
            }
        } else {
            routePanel.doRemoveRoute(selectedRoute);
            getSelectedRoute().removePoint(element);
            routePanel.addRoute(selectedRoute);
            onRouteLayerSelected(selectedRoute);
        }

    }

    /**
     * Handle a ListDataEvent signallying a drag-reordering of the map layers.
     * The event is published by the list model after the layers have been
     * reordered there.
     *
     * @param ev the event
     */
    private void onReorderPoints(ListDataEvent ev) {
        //pane.setRepaint(false);

        DirectPosition2D points[] = new DirectPosition2D[listModel.getSize()];
        for (int pos = 0; pos < listModel.getSize(); pos++) {
            RoutePoint point = listModel.getElementAt(pos);
            points[pos] = new DirectPosition2D(((Point) point.getFeature().getDefaultGeometry()).getX(), ((Point) point.getFeature().getDefaultGeometry()).getY());
        }
        routePanel.doRemoveRoute(selectedRoute);
        selectedRoute.reorderPoints(points);
        routePanel.addRoute(selectedRoute);
        onRouteLayerSelected(selectedRoute);
        //pane.setRepaint(true);
        pane.repaint();
    }

    private void onShowAllLayers() {
        if (pane != null && pane.getMapContext() != null) {
            for (MapLayer layer : pane.getMapContext().getLayers()) {
                if (!layer.isVisible()) {
                    layer.setVisible(true);
                }
            }
        }
    }

    private void onHideAllLayers() {
        if (pane != null && pane.getMapContext() != null) {
            for (MapLayer layer : pane.getMapContext().getLayers()) {
                if (layer.isVisible()) {
                    layer.setVisible(false);
                }
            }
        }
    }

    private void onSelectAllLayers() {
        if (pane != null && pane.getMapContext() != null) {
            for (MapLayer layer : pane.getMapContext().getLayers()) {
                if (!layer.isSelected()) {
                    layer.setSelected(true);
                }
            }
        }
    }

    private void onUnselectAllLayers() {
        if (pane != null && pane.getMapContext() != null) {
            for (MapLayer layer : pane.getMapContext().getLayers()) {
                if (layer.isSelected()) {
                    layer.setSelected(false);
                }
            }
        }
    }
}
